package com.tc.activiti.activiti.web.form.dynamic;

import cn.hutool.core.collection.CollUtil;
import com.tc.activiti.activiti.util.BeanUtils;
import com.tc.activiti.activiti.util.Page;
import com.tc.activiti.activiti.util.PageUtil;
import com.tc.activiti.activiti.util.UserUtil;
import com.tc.activiti.base.constants.PageConstants;
import com.tc.activiti.base.constants.StateEnum;
import com.tc.activiti.base.entity.APIRequest;
import com.tc.activiti.base.entity.APIResult;
import com.tc.activiti.user.entity.SysUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.identity.User;
import org.activiti.engine.impl.form.StartFormDataImpl;
import org.activiti.engine.impl.form.TaskFormDataImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.Map.Entry;

/**
 * 动态表单Controller
 */
@Api(value = "动态表单流程管理器", tags = "动态表单流程管理器")
@Controller
@RequestMapping(value = "/bpmn/form/dynamic")
public class DynamicFormController2 {

    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private FormService formService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RuntimeService runtimeService;

    /**
     * 读取所有的流程列表
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "读取所有的流程列表", notes = "读取所有的流程列表")
    @RequestMapping(value = "/processlist", method = RequestMethod.POST)
    @ResponseBody
    public APIResult processDefinitionList(@RequestBody APIRequest request) {
        APIResult<Page> result = new APIResult<>();
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(PageUtil.PAGE_SIZE);
        try {
            Integer pageSize = request.getRequestPage().getLimit();
            Integer pageNo = request.getRequestPage().getPageNo();
            if (pageNo == null) pageNo = PageConstants.DEFAULT_PAGE_NO;
            if (pageSize == null) pageSize = PageConstants.DEFAULT_PAGE_SIZE;
            int[] pageParams = PageUtil.init(pageNo, pageSize);
            ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().orderByDeploymentId().desc();
            List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(pageParams[0], pageParams[1]);
            if (CollUtil.isNotEmpty(processDefinitionList)) {
                for (ProcessDefinition processDefinition : processDefinitionList) {
                    Map<String, Object> values = new HashMap<>();
                    values.put("id", processDefinition.getId());
                    values.put("name", processDefinition.getName());
                    values.put("key", processDefinition.getKey());
                    values.put("version", processDefinition.getVersion());
                    values.put("diagramResourceName", processDefinition.getDiagramResourceName());
                    values.put("category", processDefinition.getCategory());
                    values.put("description", processDefinition.getDescription());
                    values.put("resourceName", processDefinition.getResourceName());
                    listMap.add(values);
                }
            }
            page.setTotalCount(processDefinitionQuery.count());
            page.setResult(listMap);
            result.setData(page);
            result.setMessage("查询流程定义列表成功");
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/processlist", e);
        }
        return result;
    }

    /**
     * 初始化启动流程，读取启动流程的表单字段来渲染start form
     */
    @ApiOperation(value = "读取启动流程的表单", notes = "读取启动流程的表单")
    @RequestMapping(value = "/get-form/start/{processDefinitionId}", method = RequestMethod.GET)
    @ResponseBody
    public APIResult findStartForm(@PathVariable("processDefinitionId") String processDefinitionId) {
        APIResult result = new APIResult<>();
        try {
            Map<String, Object> resultMap = new HashMap<>();
            StartFormDataImpl startFormData = (StartFormDataImpl) formService.getStartFormData(processDefinitionId);
            startFormData.setProcessDefinition(null);
            // 读取enum类型数据，用于下拉框
            List<FormProperty> formProperties = startFormData.getFormProperties();
            if (CollUtil.isNotEmpty(formProperties)) {
                for (FormProperty formProperty : formProperties) {
                    Map<String, String> values = (Map<String, String>) formProperty.getType().getInformation("values");
                    if (values != null) {
                        for (Entry<String, String> enumEntry : values.entrySet()) {
                            logger.debug("enum, key: {}, value: {}", enumEntry.getKey(), enumEntry.getValue());
                        }
                        resultMap.put("enum_" + formProperty.getId(), values);
                    }
                }
            }
            resultMap.put("form", startFormData);
            result.setData(resultMap);
            result.setMessage("读取启动流程的表单成功");
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/get-form/start/" + processDefinitionId, e);
        }
        return result;
    }

    /**
     * 读取Task的表单
     */
    @ApiOperation(value = "读取Task的表单", notes = "读取Task的表单")
    @RequestMapping(value = "/get-form/task/{taskId}", method = RequestMethod.GET)
    @ResponseBody
    public APIResult findTaskForm(@PathVariable("taskId") String taskId) {
        APIResult result = new APIResult<>();
        try {
            Map<String, Object> resultMap = new HashMap<>();
            TaskFormDataImpl taskFormData = (TaskFormDataImpl) formService.getTaskFormData(taskId);
            // 设置task为null，否则输出json的时候会报错
            taskFormData.setTask(null);
            resultMap.put("taskFormData", taskFormData);
            //读取enum类型数据，用于下拉框
            List<FormProperty> formProperties = taskFormData.getFormProperties();
            if (CollUtil.isNotEmpty(formProperties)) {
                for (FormProperty formProperty : formProperties) {
                    Map<String, String> values = (Map<String, String>) formProperty.getType().getInformation("values");
                    if (values != null) {
                        for (Entry<String, String> enumEntry : values.entrySet()) {
                            logger.debug("enum, key: {}, value: {}", enumEntry.getKey(), enumEntry.getValue());
                        }
                        resultMap.put(formProperty.getId(), values);
                    }
                }
            }
            result.setData(resultMap);
            result.setMessage("获取task表单成功");
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/get-form/task/" + taskId, e);
        }
        return result;
    }

    /**
     * 办理任务，提交task的并保存form
     */
    @ApiOperation(value = "办理任务", notes = "办理任务")
    @RequestMapping(value = "/task/complete/{taskId}", method = RequestMethod.POST)
    @ResponseBody
    public APIResult completeTask(@PathVariable("taskId") String taskId, HttpServletRequest request) {
        APIResult result = new APIResult<>();
        try {
            Map<String, String> formProperties = new HashMap<String, String>();
            // 从request中读取参数然后转换
            Map<String, String[]> parameterMap = request.getParameterMap();
            Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
            for (Entry<String, String[]> entry : entrySet) {
                String key = entry.getKey();
                // fp_的意思是form paremeter
                if (StringUtils.defaultString(key).startsWith("fp_")) {
                    formProperties.put(key.split("_")[1], entry.getValue()[0]);
                }
            }
            logger.debug("start form parameters: {}", formProperties);
            SysUser user = UserUtil.getUserFromSession(request.getSession());
            // 用户未登录不能操作，实际应用使用权限框架实现，例如Spring Security、Shiro等
            ProcessInstance processInstance = null;
            if (user == null || StringUtils.isBlank(user.getUserId().toString())) {
                throw new RuntimeException("用户未登录，不能操作");
            } else {
                identityService.setAuthenticatedUserId(user.getUserId().toString());
                formService.submitTaskFormData(taskId, formProperties);
                logger.debug("start a processinstance: {}", processInstance);
                result.setMessage("任务完成：taskId=" + taskId);
                result.setState(200);
            }
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/task/complete/" + taskId, e);
        } finally {
            identityService.setAuthenticatedUserId(null);
        }
        return result;
    }

    /**
     * 提交启动流程
     */
    @ApiOperation(value = "提交启动流程", notes = "提交启动流程")
    @RequestMapping(value = "/start-process/{processDefinitionId}", method = RequestMethod.POST)
    @ResponseBody
    public APIResult submitStartFormAndStartProcessInstance(@PathVariable("processDefinitionId") String processDefinitionId,
                                                            HttpServletRequest request) {
        APIResult result = new APIResult<>();
        try {
            Map<String, String> formProperties = new HashMap<String, String>();
            // 从request中读取参数然后转换
            Map<String, String[]> parameterMap = request.getParameterMap();
            Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
            for (Entry<String, String[]> entry : entrySet) {
                String key = entry.getKey();
                // fp_的意思是form paremeter
                if (StringUtils.defaultString(key).startsWith("fp_")) {
                    formProperties.put(key.split("_")[1], entry.getValue()[0]);
                }
            }
            logger.debug("start form parameters: {}", formProperties);
            SysUser user = UserUtil.getUserFromSession(request.getSession());
            // 用户未登录不能操作，实际应用使用权限框架实现，例如Spring Security、Shiro等
            ProcessInstance processInstance = null;
            if (user == null || StringUtils.isBlank(user.getUserId().toString())) {
                throw new RuntimeException("用户未登录，不能操作");
            } else {
                identityService.setAuthenticatedUserId(user.getUserId().toString());
                processInstance = formService.submitStartFormData(processDefinitionId, formProperties);
                logger.debug("start a processinstance: {}", processInstance);
                result.setMessage("启动成功，流程ID：" + processInstance.getId());
                result.setState(200);
            }
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/start-process/" + processDefinitionId, e);
        } finally {
            identityService.setAuthenticatedUserId(null);
        }
        return result;
    }


    /**
     * 获取获选人待办任务列表
     *
     * @param request
     * @param servletRequest
     * @return
     */
    @ApiOperation(value = "获取获选人待办任务列表", notes = "获取获选人待办任务列表")
    @RequestMapping(value = "/task/list", method = RequestMethod.POST)
    @ResponseBody
    public APIResult taskList(@RequestBody(required = true) APIRequest request,
                              HttpServletRequest servletRequest) {
        APIResult<Page> result = new APIResult<>();
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(PageUtil.PAGE_SIZE);
        SysUser user = UserUtil.getUserFromSession(servletRequest.getSession());
        if (BeanUtils.isEmpty(user)) {
            throw new RuntimeException("请先登录在操作");
        }
        try {
            Integer pageSize = request.getRequestPage().getLimit();
            Integer pageNo = request.getRequestPage().getPageNo();
            if (pageNo == null) pageNo = PageConstants.DEFAULT_PAGE_NO;
            if (pageSize == null) pageSize = PageConstants.DEFAULT_PAGE_SIZE;
            int[] pageParams = PageUtil.init(pageNo, pageSize);
            //获取获选人待办任务列表
            TaskQuery taskQuery = taskService.createTaskQuery();
            List<Task> tasks = taskQuery.taskCandidateOrAssigned(user.getUserId().toString()).active().orderByTaskId().desc().listPage(pageParams[0], pageParams[1]);
            if (CollUtil.isNotEmpty(tasks)) {
                for (Task task : tasks) {
                    Map<String, Object> values = new HashMap<>();
                    values.put("id", task.getId());
                    values.put("name", task.getName());
                    values.put("category", task.getCategory());
                    values.put("assignee", task.getAssignee());
                    values.put("description", task.getDescription());
                    values.put("processDefinitionId", task.getProcessDefinitionId());
                    values.put("owner", task.getOwner());
                    values.put("formKey", task.getFormKey());
                    values.put("taskDefinitionKey", task.getTaskDefinitionKey());
                    listMap.add(values);
                }
            }
            page.setTotalCount(taskQuery.count());
            page.setResult(listMap);
            result.setData(page);
            result.setMessage("获取获选人待办任务列表成功");
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/task/list", e);
        }
        return result;
    }


    /**
     * 签收任务
     *
     * @param taskId
     * @param session
     * @return
     */
    @ApiOperation(value = "签收任务", notes = "签收任务")
    @RequestMapping(value = "/task/claim/{id}", method = RequestMethod.GET)
    @ResponseBody
    public APIResult claim(@PathVariable("id") String taskId, HttpSession session) {
        APIResult result = new APIResult<>();
        try {
            String userId = UserUtil.getUserFromSession(session).getUserId().toString();
            if (BeanUtils.isEmpty(userId)) {
                throw new RuntimeException("请先登录再操作");
            }
            taskService.claim(taskId, userId);
            result.setMessage("签收任务成功");
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/task/claim/" + taskId, e);
        }
        return result;
    }

    /**
     * 运行中的流程实例  只有权限查看自己的，如果是管理员，查看全部的运行流程实例
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "运行中的流程实例", notes = "运行中的流程实例")
    @RequestMapping(value = "/process-instance/running/list", method = RequestMethod.POST)
    @ResponseBody
    public APIResult running(@RequestBody(required = true) APIRequest request) {
        APIResult<Page> result = new APIResult<>();
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(PageUtil.PAGE_SIZE);
        try {
            Integer pageSize = request.getRequestPage().getLimit();
            Integer pageNo = request.getRequestPage().getPageNo();
            if (pageNo == null) pageNo = PageConstants.DEFAULT_PAGE_NO;
            if (pageSize == null) pageSize = PageConstants.DEFAULT_PAGE_SIZE;
            int[] pageParams = PageUtil.init(pageNo, pageSize);
            ProcessInstanceQuery dynamicQuery = runtimeService.createProcessInstanceQuery().orderByProcessInstanceId().desc().active();
            List<ProcessInstance> list = dynamicQuery.listPage(pageParams[0], pageParams[1]);
            if (CollUtil.isNotEmpty(list)) {
                for (ProcessInstance processInstance : list) {
                    Map<String, Object> values = new HashMap<String, Object>();
                    values.put("id", processInstance.getId());
                    values.put("name", processInstance.getName());
                    values.put("businessKey", processInstance.getBusinessKey());
                    values.put("deploymentId", processInstance.getDeploymentId());
                    values.put("description", processInstance.getDescription());
                    values.put("processDefinitionId", processInstance.getProcessDefinitionId());
                    values.put("processDefinitionName", processInstance.getProcessDefinitionName());
                    values.put("processDefinitionVersion", processInstance.getProcessDefinitionVersion());
                    listMap.add(values);
                }
            }
            page.setTotalCount(dynamicQuery.count());
            page.setResult(listMap);
            result.setData(page);
            result.setMessage("查询运行中的流程成功");
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/process-instance/running/list", e);
        }
        return result;
    }


    /**
     * 已结束的流程实例
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "已结束的流程", notes = "已结束的流程")
    @RequestMapping(value = "/process-instance/finished/list", method = RequestMethod.POST)
    @ResponseBody
    public APIResult finished(@RequestBody(required = true) APIRequest request) {
        APIResult<Page> result = new APIResult<>();
        List<Map<String, Object>> listMap = new ArrayList<>();
        Page<Map<String, Object>> page = new Page<>(PageUtil.PAGE_SIZE);
        try {
            Integer pageSize = request.getRequestPage().getLimit();
            Integer pageNo = request.getRequestPage().getPageNo();
            if (pageNo == null) pageNo = PageConstants.DEFAULT_PAGE_NO;
            if (pageSize == null) pageSize = PageConstants.DEFAULT_PAGE_SIZE;
            int[] pageParams = PageUtil.init(pageNo, pageSize);
            HistoricProcessInstanceQuery dynamicQuery = historyService.createHistoricProcessInstanceQuery().finished().orderByProcessInstanceEndTime().desc();
            List<HistoricProcessInstance> list = dynamicQuery.listPage(pageParams[0], pageParams[1]);
            if (CollUtil.isNotEmpty(list)) {
                for (HistoricProcessInstance historicProcessInstance : list) {
                    Map<String, Object> values = new HashMap<String, Object>();
                    values.put("id", historicProcessInstance.getId());
                    values.put("name", historicProcessInstance.getName());
                    values.put("businessKey", historicProcessInstance.getBusinessKey());
                    values.put("deploymentId", historicProcessInstance.getDeploymentId());
                    values.put("description", historicProcessInstance.getDescription());
                    values.put("processDefinitionId", historicProcessInstance.getProcessDefinitionId());
                    values.put("processDefinitionName", historicProcessInstance.getProcessDefinitionName());
                    values.put("processDefinitionVersion", historicProcessInstance.getProcessDefinitionVersion());
                    listMap.add(values);
                }
            }
            page.setTotalCount(dynamicQuery.count());
            page.setResult(listMap);
            result.setData(page);
            result.setMessage("查询运行结束的流程成功");
        } catch (Exception e) {
            result.setState(StateEnum.ERROR_BPMN.getCode());
            result.setMessage(StateEnum.ERROR_BPMN.getText());
            result.setCause(e.getMessage());
            logger.error("/bpmn/form/dynamic/process-instance/finished/list", e);
        }
        return result;
    }

}
